home *** CD-ROM | disk | FTP | other *** search
- From: decvax!vax135!hou3c!ka
- Date: Mon, 21 Jan 85 22:38:18 est
- Newsgroups: mod.sources
- Subject: Vnews part 5
-
- # Welcome to vnews release 2.11-B 1/17/85.
- # This is part 5 out of 7.
- # Feed me into sh (NOT csh).
-
- if test ! -d postnews
- then mkdir postnews
- fi
-
- cat > postnews/postnews.c <<\!E!O!F!
- /*
- * Postnews: post a news message to Usenet. This C version replaces a shell
- * script, and does more intelligent prompting and filtering than possible
- * in a shell script.
- */
-
- #ifndef lint
- static char *SccsId = "@(#)postnews.c 1.16 9/18/84";
- #endif !lint
-
- /* #include "params.h" */
- #include "config.h"
- #include "defs.h"
- #include "libextern.h"
- #include <stdio.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <grp.h>
- #include <pwd.h>
- #include <sys/stat.h>
- #include <ctype.h>
- #include <time.h>
-
- char tempfname[50]; /* file name used for making article */
- char original[BUFLEN]; /* file name of original, used in followup */
- char homedir[BUFLEN]; /* HOME environment setting */
- char ccname[BUFLEN]; /* file name for article copy */
-
- /* article header information */
- char subject[BUFLEN];
- char distribution[BUFLEN];
- char references[BUFLEN];
- char newsgroups[BUFLEN];
- char moderator[BUFLEN];
-
- char *Progname = "postnews"; /* for xerror */
-
- time_t fmodtime;
- int ismod = 0;
- char buf[BUFLEN];
-
- struct distr {
- char abbr[24];
- char descr[128];
- } distr[16];
-
- extern struct passwd *getpwnam(), *getpwuid(), *getpwent();
- FILE *ckfopen();
-
- main(argc, argv)
- char *argv[];
- {
- init();
-
- if (argc == 2) {
- if (strncmp(SPOOL, argv[1], strlen(SPOOL)))
- xerror("Can only followup to articles in %s", SPOOL);
- followup(argv[1]);
- strcpy(original, argv[1]);
- } else
- if (askyes("Is this message in response to some other message? ","no")) {
- char ng[BUFLEN], num[BUFLEN];
- long i, j;
- register char *c;
- int fd;
- char canpost;
-
- getpr("In what newsgroup was the article posted? ",ng);
- if (!valid_ng(ng, &i, &j, &canpost))
- if (canpost != 'n' )
- byebye("There is no such newsgroup.");
- else
- byebye("You are not allowed to post to that group.");
-
- for(;;) {
- getpr("\nWhat was the article number? (type ? for help) ", num);
- if (num[0] == 0)
- continue;
- else if (num[0] == '/') {
- artlist(ng, num + 1) ;
- continue ;
- }
- else if (num[0] == '?') {
- printf("Valid article numbers are from %ld to %ld\n", j, i);
- printf("Type /string to get a list of articles containing string\nin the author or title fields.\n");
- continue;
- }
- sprintf(original, "%s/%s", SPOOL, ng);
- for (c=original+strlen(SPOOL)+1; *c ;++c)
- if (*c == '.')
- *c = '/';
- strcat(original, "/");
- strcat(original, num);
-
- if ((fd=open(original,0)) >= 0) {
- close(fd);
- printf("\narticle %s\n", original);
- if (article_line(original, "From: ", buf))
- printf("%s\n", buf);
- if (article_line(original, "Subject: ", buf))
- printf("%s\n", buf);
- if (askyes("Is this the one you want? ", ""))
- break;
- } else
- printf("I can't find that article.\n");
- }
-
- followup(original);
- } else {
- do {
- getpr("Subject: ", subject);
- } while (*subject == '\0');
-
- while (!get_newsgroup())
- ;
- get_distribution();
- }
-
- if (pre_checks())
- exit(1);
- edit_article();
- post_checks();
-
- post_article();
- }
-
- /*
- * Find out the topic of interest.
- */
- get_newsgroup()
- {
- int n;
- long i;
- char canpost;
-
- printf("Newsgroups (enter one at a time, end with a blank line):\n");
- printf("For a list of newsgroups, type ?\n");
- n = 0;
- newsgroups[0] = '\0';
-
- for(;;) {
- getpr("> ", buf);
- if (buf[0] == '\0')
- if (n == 0)
- return FALSE;
- else
- return TRUE;
- if (buf[0] == '?'){
- /* too lazy to do it myself.... */
- printf("These are the currently active groups:\n");
- sprintf(buf,"exec cat %s/newsgroups", LIB);
- system(buf);
- continue;
- }
- if (valid_ng(buf, &i, &i, &canpost)) {
- if (n++ != 0)
- strcat(newsgroups, ",");
- strcat(newsgroups, buf);
- } else {
- if (canpost == 'n')
- printf("You are not allowed to post to %s\n",
- buf);
- else
- printf("%s is not a valid newsgroup.\n", buf);
- }
- }
- }
-
- /*
- * Find out how widely the author wants the message distributed.
- */
- get_distribution()
- {
- register int i;
- register char *r;
- char def[BUFLEN];
- char *index();
-
- strcpy(def, newsgroups);
- r = index(def, '.');
- if (r) {
- *r = '\0';
- if (strcmp(def, "net") == 0)
- strcpy(def, "world");
- } else
- strcpy(def, "local");
-
- if (strcmp(def,"to") == 0) {
- distribution[0] = '\0';
- return; /* He's probably testing something */
- }
- if (ngmatch("net.test", newsgroups))
- strcpy(def, "local");
- for(;;) {
- sprintf(buf, "Distribution (default='%s', '?' for help) : ", def);
- getpr(buf, distribution);
- if (distribution[0] == '\0')
- strcpy(distribution, def);
-
- /* Did the user ask for help? */
- if (distribution[0] == '?') {
- printf("How widely should your article be distributed?\n");
- for (i=0; distr[i].abbr[0]; i++)
- printf("%s\t%s\n", distr[i].abbr, distr[i].descr);
- continue;
- }
-
- /* Check that it's a proper distribution */
- for (i=0; distr[i].abbr[0]; i++) {
- if (strncmp(distr[i].abbr, distribution, sizeof(distr[0].abbr)) == 0) {
- /* Found a match. Do any special rewriting. */
- if (strcmp(distribution, "world") == 0)
- strcpy(distribution, "net");
- return;
- }
- }
-
- printf("Type ? for help.\n");
- }
- }
-
- /*
- * Do sanity checks before the author types in the message.
- */
- pre_checks()
- {
- check_mod();
- if (recording(newsgroups))
- return 1;
- return 0;
- }
-
- /*
- * Check to see if the newsgroup is moderated.
- */
- check_mod()
- {
- register FILE *fd;
- char ng[64], mod[BUFLEN];
-
- sprintf(buf, "%s/%s", LIB, "moderators");
- fd = ckfopen(buf, "r");
-
- while (!feof(fd)) {
- if (fgets(buf, sizeof buf, fd) == NULL) {
- fclose(fd);
- return;
- }
- twosplit(buf, ng, mod);
- if (ngmatch(newsgroups, ng)) {
- strcpy(moderator, mod);
- ismod = 1;
- return;
- }
- }
- }
-
- /*
- * Set up the temp file with headers.
- */
- edit_article()
- {
- FILE *tf, *of;
- char *editor;
- char *endflag = "";
- char *p;
- char *getenv();
- struct stat stbuf;
-
- editor = getenv("EDITOR");
- strcpy(tempfname, "/tmp/postXXXXXX");
- mktemp(tempfname);
-
- /* insert a header */
- tf = ckfopen(tempfname, "w");
- fprintf(tf, "Subject: %s\n", subject);
- fprintf(tf, "Newsgroups: %s\n", newsgroups);
- if (distribution[0] != '\0')
- fprintf(tf, "Distribution: %s\n", distribution);
- if (ismod)
- fprintf(tf, "To: %s\n", moderator);
-
- if (references[0] != '\0') {
- fprintf(tf, "References: %s\n\n", references);
-
- of = ckfopen(original, "r");
- while (fgets(buf, BUFSIZ, of) != NULL)
- if (buf[0] == '\n') /* skip headers */
- break;
- while (fgets(buf, BUFSIZ, of) != NULL)
- fprintf(tf, "> %s", buf);
- fclose(of);
- }
-
- fprintf(tf, "\n*** REPLACE THIS LINE WITH YOUR MESSAGE ***\n");
- fflush(tf);
- fstat(fileno(tf), &stbuf);
- fmodtime = stbuf.st_mtime;
- fclose(tf);
-
- /* edit the file */
- if (editor == NULL)
- editor = DFTEDITOR;
-
- p = editor + strlen(editor) - 2;
- if (strcmp(p, "vi") == 0 && references[0] == '\0')
- endflag = "+";
-
- sprintf(buf, "exec %s %s %s", editor, endflag, tempfname);
-
- system(buf);
- }
-
- /*
- * Do sanity checks after the author has typed in the message.
- */
- post_checks()
- {
- char group[BUFLEN];
- char s[BUFLEN + 24];
- char *c;
- struct stat stbuf;
-
- if (stat(tempfname, &stbuf) < 0) {
- printf("File deleted - no message posted.\n");
- unlink(tempfname);
- exit(1);
- }
-
- if (stbuf.st_mtime == fmodtime || stbuf.st_size < 5) {
- printf("File not modified - no message posted.\n");
- unlink(tempfname);
- exit(1);
- }
-
- /* Sanity checks for certain newsgroups */
- if (ngmatch(newsgroups, "all.wanted") && ngmatch(distribution,"net,na,usa,att,btl")) {
- printf("Is your message something that might go in your local\n");
- printf("newspaper, for example a used car ad, or an apartment\n");
- printf("for rent? ");
- if (askyes("","")) {
- printf("It's pointless to distribute your article widely, since\n");
- printf("people more than a hundred miles away won't be interested.\n");
- printf("Please use a more restricted distribution.\n");
- get_distribution();
- modify_article(tempfname,"Distribution: ",distribution,"replace");
- }
- }
-
- if (ngmatch(newsgroups, "all.jokes")) {
- if (askyes("Could this be offensive to anyone? ","")) {
- getpr("Whom might it offend? ", group);
- sprintf(s," - offensive to %s (ROT13)",group);
- modify_article(tempfname, "Subject: ", s, "append");
- encode(tempfname);
- }
- }
-
- if (ngmatch(newsgroups, "net.general")) {
- c = newsgroups;
- while (*c != ',' && *c)
- ++c;
- if (*c == ',') {
- printf("Everybody reads net.general, so it doesn't make sense to\n");
- printf("post to newsgroups in addition to net.general. If your\n");
- printf("article belongs in one of these other newsgroups, then you\n");
- printf("should not post to net.general. If it is important enough\n");
- printf("for net.general, then you shouldn't post it in other places\n");
- printf("as well. Please reenter the newsgroups.\n");
- get_newsgroup();
- modify_article(tempfname,"Newsgroups: ",newsgroups,"replace");
- }
- else {
- printf("net.general is for important announcements.\n");
- printf("It is not for items for which you couldn't think\n");
- printf("of a better place - those belong in net.misc.\n");
- if (!askyes("Are you sure your message belongs in net.general? ","")) {
- get_newsgroup();
- modify_article(tempfname, "Newsgroups: ", newsgroups, "replace");
- }
- }
- }
- }
-
- /*
- * Save a copy of the article in the users NEWSARCHIVE directory.
- */
- save_article()
- {
- FILE *in, *out;
- int c;
- time_t timenow, time();
- char *today, *ctime();
-
-
- in = ckfopen(tempfname, "r");
- out = ckfopen(ccname, "a");
- timenow = time((time_t)0);
- today = ctime(&timenow);
- fprintf(out,"From postnews %s",today);
- while ((c=getc(in)) != EOF)
- putc(c, out);
- putc('\n', out);
- fclose(in);
- fclose(out);
- }
-
- /*
- * Post the article to the net.
- */
- post_article()
- {
- extern char MAILPARSER[];
- int status;
-
- printf("%s article...\n", ismod ? "Mailing" : "Posting" );
- if (ismod)
- sprintf(buf, "exec %s -t < %s", MAILPARSER, tempfname);
- else
- sprintf(buf, "exec %s -wi < %s", POSTNM, tempfname);
- status = system(buf);
-
- if (status) {
- printf("Article not %s - exit status %d\n", ismod ? "mailed" : "posted", status);
- savedead();
- } else {
- printf("Article %s successfully.\n", ismod ? "mailed" : "posted" );
- if (ccname[0]) {
- if (ismod)
- save_article();
- printf("A copy has been saved in %s\n", ccname);
- }
- }
- unlink(tempfname);
- }
-
- /*
- * Save an article that couldn't be posted.
- */
- savedead() {
- FILE *in, *out;
- char deadfile[256];
- int c;
-
- in = ckfopen(tempfname, "r");
- sprintf(deadfile, "%s/dead.article", homedir);
- out = ckfopen(deadfile, "a");
- while ((c = getc(in)) != EOF)
- putc(c, out);
- putc('\n', out);
- fclose(in);
- fclose(out);
- printf("Article saved in %s\n", deadfile);
- }
-
- /*
- * Initialization.
- */
- init()
- {
- FILE *fd;
- register char *p;
- int i;
- char *getenv();
-
- references[0] = '\0';
- distribution[0] = '\0';
-
- p = getenv("HOME");
- if (p == NULL) {
- p = getenv("LOGDIR");
- if (p == NULL) {
- struct passwd *pw;
- pw = getpwuid(getuid());
- if (pw == NULL) {
- fprintf(stderr,"You're not in /etc/passwd\n");
- exit(1);
- }
- p = pw->pw_dir;
- }
- }
- strcpy(homedir, p);
-
-
- p = getenv("NEWSARCHIVE");
- if (p != NULL)
- strcpy(ccname, p);
- /*
- else
- sprintf(ccname, "%s/author_copy", homedir);
- */
-
- pathinit();
- sprintf(buf, "%s/%s", LIB, "distributions");
- fd = ckfopen(buf, "r");
- for (i=0; !feof(fd); i++) {
- if (fgets(buf, sizeof buf, fd) == NULL)
- break;
- twosplit(buf, distr[i].abbr,distr[i].descr);
- }
- fclose(fd);
- }
-
- /*
- * Split a line of the form
- * text whitespace text
- * into two strings. Also trim off any trailing newline.
- * This is destructive on src.
- */
- twosplit(src, dest1, dest2)
- char *src, *dest1, *dest2;
- {
- register char *p;
-
- nstrip(src);
- for (p=src; isalnum(*p) || ispunct(*p); p++)
- ;
- *p++ = 0;
- for ( ; isspace(*p); p++)
- ;
- strcpy(dest1, src);
- strcpy(dest2, p);
- }
-
- /*
- * Get a yes or no answer to a question. A default may be used.
- */
- askyes(msg, def)
- char *msg, *def;
- {
-
- printf("%s", msg);
- buf[0] = 0;
- gets(buf);
- switch(buf[0]) {
- case 'y':
- case 'Y':
- return TRUE;
- case 'n':
- case 'N':
- return FALSE;
- case '\0':
- switch(*def) {
- case 'y':
- case 'Y':
- return TRUE;
- case 'n':
- case 'N':
- return FALSE;
- }
- default:
- printf("Please answer yes or no.\n");
- return askyes(msg, def);
- }
- }
-
- /*
- * Get a character string into buf, using prompt msg.
- */
- getpr(msg, bfr)
- char *msg, *bfr;
- {
- static int numeof = 0;
- printf("%s", msg);
- gets(bfr);
- nstrip(bfr);
- if (feof(stdin)) {
- if (numeof++ > 3) {
- fprintf(stderr,"Too many EOFs\n");
- exit(1);
- }
- clearerr(stdin);
- }
- }
-
- byebye(mesg)
- char *mesg;
- {
- printf("%s\n", mesg);
- exit(1);
- }
-
- /*
- * make a modification to the header of an article
- *
- * fname -- name of article
- * field -- header field to modify
- * line -- modification line
- * how -- 'a' or 'A' to append line to existing header line
- * anything else to replace existing line
- *
- * example:
- * modify_article("/tmp/article" , "Subject: " , "new subject" , "replace");
- *
- *
- */
- modify_article(fname, field, line, how)
- char *fname, *field, *line, *how;
- {
- FILE *fpart, *fptmp;
- char *temp2fname = "/tmp/postXXXXXX";
- int i;
-
- mktemp(temp2fname);
-
- fptmp = ckfopen(temp2fname, "w");
- fpart = ckfopen(fname, "r");
-
- i = strlen(field);
- while (fgets(buf, BUFLEN, fpart) != NULL) {
- if (strncmp(field, buf, i) == 0) {
- nstrip(buf);
- if (*how=='a' || *how=='A')
- /* append to current field */
- sprintf(buf, "%s%s\n", buf, line);
- else
- /* replace current field */
- sprintf(buf, "%s%s\n", field, line);
- }
- fputs(buf, fptmp);
- }
-
- fclose(fpart);
- fclose(fptmp);
-
- fptmp = ckfopen(temp2fname, "r");
- fpart = ckfopen(fname, "w");
-
- i = strlen(field);
- while (fgets(buf,BUFLEN,fptmp) != NULL)
- fputs(buf, fpart);
-
- fclose(fpart);
- fclose(fptmp);
- unlink(temp2fname);
- }
-
-
- /* verify that newsgroup exists, and get number of entries */
- valid_ng(ng, maxart, minart, canpost)
- char *ng;
- long *maxart, *minart;
- char *canpost;
- {
- char ng_check[BUFLEN], ng_read[BUFLEN];
- char ACTIVE[FPATHLEN];
- FILE *fp;
-
- *minart = 1; *canpost = 'y';
- sprintf(ACTIVE, "%s/active", LIB);
- fp = ckfopen(ACTIVE, "r");
- while (fgets(ng_read, BUFLEN, fp) != NULL) {
- sscanf(ng_read, "%s %ld %ld %c", ng_check, maxart, minart, canpost);
- if (strcmp(ng_check, ng) == 0) {
- fclose(fp);
- if (*canpost == 'y')
- return TRUE;
- else
- return FALSE;
- }
- }
- *canpost = 'i';
- *maxart = 0;
- *minart = 0;
- fclose(fp);
- return FALSE;
- }
-
- /* get the line specified by field from an article */
- article_line(article, field, line)
- char *article, *field, *line;
- {
- FILE *fp;
- char *c;
- int i = strlen(field);
-
- fp = ckfopen(article,"r");
- while ((c=fgets(line,BUFLEN,fp)) != NULL && strncmp(field,line,i) != 0)
- ;
- fclose(fp);
- if (c != NULL) {
- nstrip(line);
- return TRUE;
- } else {
- line[0] = '\0';
- return FALSE;
- }
- }
-
-
- /* get the header information for a followup article */
- followup(baseart)
- register char *baseart;
- {
- /* subject */
- if (article_line(baseart, "Subject: ", buf)) {
- if (!prefix(buf+9, "Re:"))
- sprintf(subject, "Re: %s", buf+9);
- else
- strcpy(subject, buf+9);
- } else
- strcpy(subject, "Re: orphan response");
-
- /* newsgroup */
- if (article_line(baseart, "Newsgroups: ", buf))
- strcpy(newsgroups, buf+12);
- if (ngmatch(newsgroups, "net.general"))
- strcpy(newsgroups,"net.followup");
-
- /* distribution */
- if (article_line(baseart, "Distribution: ", buf))
- strcpy(distribution, buf+14);
-
- /* references */
- if (article_line(baseart, "References: ", buf)) {
- strcpy(references, buf+12);
- strcat(references, " ");
- }
- if (article_line(baseart, "Message-ID: ", buf))
- strcat(references, buf+12);
- }
-
- encode(article)
- char *article;
- {
- FILE *fpart, *fphead, *fpcoded;
- char *headerfile = "/tmp/pheadXXXXXX";
- char *codedfile = "/tmp/pcodeXXXXXX";
-
- mktemp(headerfile);
- mktemp(codedfile);
-
- fpart = ckfopen(article, "r");
-
- /* place article header in "headerfile" file */
- fphead = ckfopen(headerfile, "w");
- while (fgets(buf, BUFLEN, fpart) != NULL) {
- fputs(buf, fphead);
- if (buf[0] == '\n')
- break;
- }
- fclose(fphead);
-
- /* place article body in "codedfile" file */
- fpcoded = ckfopen(codedfile, "w");
- while (fgets(buf, BUFLEN, fpart) != NULL)
- fputs(buf, fpcoded);
- fclose(fpcoded);
- fclose(fpart);
-
- /* encode body and put back together with header */
- rename(headerfile, article);
-
- sprintf(buf,"exec %s/%s 13 < %s >> %s\n", LIB, "caesar", codedfile, article);
- printf("Encoding article -- please stand by\n");
- if (system(buf)) {
- printf("encoding failed");
- exit(2);
- }
- unlink(codedfile);
- }
-
-
- /*
- * Print a recorded message warning the poor luser what he is doing
- * and demand that he understands it before proceeding. Only do
- * this for newsgroups listed in LIBDIR/recording.
- */
- recording(ngrps)
- char *ngrps;
- {
- char recbuf[BUFLEN];
- FILE *fd;
- char nglist[BUFLEN], fname[BUFLEN];
- int c, n, yes;
-
- sprintf(recbuf, "%s/%s", LIB, "recording");
- fd = fopen(recbuf, "r");
- if (fd == NULL)
- return 0;
- while ((fgets(recbuf, sizeof recbuf, fd)) != NULL) {
- sscanf(recbuf, "%s %s", nglist, fname);
- if (ngmatch(ngrps, nglist)) {
- fclose(fd);
- if (fname[0] == '/')
- strcpy(recbuf, fname);
- else
- sprintf(recbuf, "%s/%s", LIB, fname);
- fd = fopen(recbuf, "r");
- if (fd == NULL)
- return 0;
- while ((c = getc(fd)) != EOF)
- putc(c, stderr);
- fprintf(stderr, "Do you understand this? Hit <return> to proceed, <BREAK> to abort: ");
- n = read(2, recbuf, 100);
- c = recbuf[0];
- yes = (c=='y' || c=='Y' || c=='\n' || c=='\n' || c==0);
- if (n <= 0 || !yes)
- return -1;
- }
- }
- return 0;
- }
-
- xxit(i)
- {
- exit(i);
- }
-
-
- xerror(fmt, a1, a2, a3, a4)
- char *fmt;
- {
- fprintf(stderr, fmt, a1, a2, a3, a4);
- putc('\n', stderr);
- xxit(1);
- }
- !E!O!F!
-
- cat > postnews/postnm.1 <<\!E!O!F!
- .TH POSTNM 1
- .SH NAME
- postnm \- post mail or news
- .SH SYNOPSIS
- .B postnm
- [
- .B \-ixw
- ]
- [ header-options ]
- [ file ]
- .SH DESCRIPTION
- .I Postnm
- reads a message in ARPANET mail format from a file, or from the
- standard input if no file is given.
- It checks the message for validity. If the message contains a
- Newsgroups line, the message is posted to USENET.
- If the message contains To, Cc, or Bcc lines, it is mailed to
- the indicated addresses.
- .P
- Users who wish to invoke
- .I postnm
- directly should place their article in a file and then run postnm on it.
- .I Postnm
- makes no attempt to save an article when an error occurs, so if you try
- to type an article directly into
- .I postnm
- from the terminal, you will be forced to start all over again if something
- goes wrong.
- Now that
- .I postnm
- exists, users should never invoke inews directly.
- .SS options
- .IP -i 6
- Identify. If the file $HOME/.signature exists, append it to the message.
- .IP -x 6
- Causes postnm to print out the generated command lines without
- actually posting the message.
- .IP -w 6
- Causes postnm to wait for the postings to complete rather that running
- inews and mail in the background.
- .P
- Certain header lines can be inserted into the header of the article
- from the command line using the following options:
- .sp
- .nf
- -c Control:
- -d Distribution:
- -f From:
- -n Newsgroups:
- -R References:
- -s Subject:
- -t To:
- .fi
- .P
- The Command header is never passed to inews or mail.
- ``Command:\ reply''
- causes
- .I postnm
- to ignore the Newsgroups and Distribution lines, and ``Command:\ followup''
- causes
- .I postnm
- to ignore the To lines.
- .P
- If the environment variable NEWSARCHIVE is set, it specifies a file in which
- copies of all news (but not mail) articles are to be placed.
- .SH EXAMPLE
- postnm -c 'cancel <123@hou3c.UUCP>' -n net.misc /dev/null
- .in +5
- Cancel article <123@hou3c.UUCP>.
- .B /dev/null
- provides an empty article body.
- .in -5
- .SH FILES
- .nf
- /usr/lib/news/active list of newsgroups
- /usr/lib/news/moderators addresses of newsgroup moderators
- /usr/lib/news/distributions list of distributions (optional)
- $HOME/.signature signature file
- .SH AUTHOR
- Kenneth Almquist (ihnp4!hou3c!ka)
- !E!O!F!
-
- cat > postnews/postnm.h <<\!E!O!F!
- /*
- * This program handles the posting or mailing of replies and followups
- * for vnews. It can also be invoked directly.
- *
- * Copyright 1984 by Kenneth Almquist. All rights reserved.
- * Permission is granted for anyone to use and distribute, but not
- * sell, this program provided that this copyright notice is retained.
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h> /* for .signature kludge */
- #include <signal.h>
- #include "config.h"
- #include "newsdefs.h"
- #include "libextern.h"
- #include "str.h"
- #include "time.h"
-
- extern char *scanp; /* string scanning pointer */
-
- #define MODGROUPS "fa.all,mod.all,all.mod,all.announce"
-
- /* types of header fields */
- #define HTTO 0
- #define HTCC 1
- #define HTBCC 2
- #define HTNEWSGROUPS 3
- #define HTINREPLYTO 5
- #define HTREFERENCES 6
- #define HTSUBJECT 7
- #define HTEXPIRES 8
- #define HTFROM 9
- #define HTREPLYTO 10
- #define HTFOLLOWUPTO 11
- #define HTDIST 12
- #define HTKEYWORDS 14
- #define HTCONTROL 15
- #define HTORGANIZATION 16
- #define HTSUMMARY 17
- #define HTAPPROVED 18
- #define HTCOMMENTS 19
- #define HTMESSAGEID 20
- #define HTCOMMAND 21
- #define HTUNKNOWN 27
-
-
- struct hline {
- struct hline *next;
- short type;
- short linno;
- char *text;
- char *hdrname;
- char *body;
- char *fixed;
- };
-
- #ifndef EXTERN
- #define EXTERN extern
- #define INIT(val)
- #else
- #define INIT(val) = val
- #endif
-
- EXTERN struct hline *hfirst, *hlast; /* list of header lines */
- EXTERN struct hline *hdrline[HTCOMMAND + 1]; /* indexed by type */
- EXTERN struct hline *curhdr; /* current header line */
-
-
- #define MAXADDR 100
- EXTERN char *addrlist[MAXADDR + 1]; /* mail destinations */
- EXTERN char **addrp INIT(addrlist); /* next entry in addrlist */
- EXTERN char *moderator; /* address of moderator */
- EXTERN char *references; /* specified on command line */
-
- #include "setjmp.h"
-
- #define setexit() setjmp(syntaxjmp)
- #define reset() longjmp(syntaxjmp, 1)
-
- EXTERN jmp_buf syntaxjmp; /* jump here on syntax errors */
-
- EXTERN int nerrors; /* number of errors */
- EXTERN int linno; /* input line number */
- EXTERN FILE *infp INIT(stdin); /* input file */
- EXTERN FILE *newsfp, *mailfp; /* temp files */
- EXTERN char mailtemp[32], newstemp[32]; /* temp files */
- #define MAXGRPS 10
- EXTERN char *nglist[MAXGRPS + 1]; /* entries on Newsgroup line */
- EXTERN char *follist[MAXGRPS + 1]; /* entries on Followup-To */
- EXTERN char *nlist[MAXGRPS + 1]; /* temporary */
- EXTERN int debug; /* don't actuall post message */
- EXTERN int verbose; /* verbose flag */
- EXTERN int background INIT(1); /* run mail/inews in background */
- EXTERN char *outp; /* for generating output lines */
- EXTERN int signit; /* if set, append .signiture file */
- EXTERN char signfile[FPATHLEN]; /* .signiture file */
- EXTERN int signmode; /* .signature kludge */
- EXTERN char *envkludge[200]; /* organization kludge */
-
-
- long atol();
- FILE *ckfopen();
- time_t cgtdate();
- char *ckmalloc();
-
- char *getval();
- !E!O!F!
-
- cat > postnews/postnm1.c <<\!E!O!F!
- /*
- * Main routine and error printing routines.
- *
- * Copyright 1984 by Kenneth Almquist. All rights reserved.
- * Permission is granted for anyone to use and distribute, but not
- * sell, this program provided that this copyright notice is retained.
- */
-
- #define EXTERN
- #include "postnm.h"
-
-
- int xxit();
-
-
- main(argc, argv)
- char **argv;
- {
- int c;
- FILE *fp;
- extern char *optarg;
- extern int optind;
-
- pathinit();
- getuser();
- while ((c = getopt(argc, argv, "ivBwxc:d:f:n:R:s:t:")) != EOF) {
- switch (c) {
- case 'i':
- signit = 1;
- break;
- case 'v':
- verbose = 1;
- break;
- case 'B':
- background = 1;
- break;
- case 'w':
- background = 0;
- break;
- case 'x':
- debug++;
- background = 0;
- break;
- case 'c':
- sprintf(bfr, "Control: %s\n", optarg);
- prochdr(bfr, 1);
- break;
- case 'd':
- sprintf(bfr, "Distribution: %s\n", optarg);
- prochdr(bfr, 1);
- break;
- case 'f':
- sprintf(bfr, "From: %s\n", optarg);
- prochdr(bfr, 1);
- break;
- case 'n':
- sprintf(bfr, "Newsgroups: %s\n", optarg);
- prochdr(bfr, 1);
- break;
- case 'R':
- sprintf(bfr, "%s\n", optarg);
- references = savestr(bfr);
- break;
- case 's':
- sprintf(bfr, "Subject: %s\n", optarg);
- prochdr(bfr, 1);
- break;
- case 't':
- if (hdrline[HTTO] == NULL) {
- sprintf(bfr, "To: %s\n", optarg);
- } else {
- nstrip(hdrline[HTTO]->text);
- sprintf(bfr, "%s, %s\n", hdrline[HTTO]->text, optarg);
- hlzap(HTTO);
- }
- prochdr(bfr, 1);
- break;
- case '?':
- exit(1);
- }
- }
- if (optind < argc && (infp = fopen(argv[optind], "r")) == NULL)
- xerror("%s: cannot open", argv[optind]);
- if (debug) {
- strcpy(newstemp, "news.tmp");
- strcpy(mailtemp, "mail.tmp");
- } else {
- sprintf(newstemp, "/tmp/pnm%05dn", getpid());
- sprintf(mailtemp, "/tmp/pnm%05dm", getpid());
- }
-
- readheader();
-
- checkheader();
-
- if (signal(SIGINT, SIG_IGN) != SIG_IGN)
- signal(SIGINT, xxit);
- if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
- signal(SIGHUP, xxit);
-
- if (addrp != addrlist) {
- mailfp = ckfopen(mailtemp, "w");
- genmailhdr(mailfp);
- }
- if (hdrline[HTNEWSGROUPS]) {
- newsfp = ckfopen(newstemp, "w");
- gennewshdr(newsfp);
- }
-
- if (newsfp == NULL && mailfp == NULL)
- xerror("No to or newsgroup line specified");
- if (nerrors)
- xxit(1);
-
- addbody(infp);
- if (signit) {
- getuser();
- sprintf(bfr, "%s/.signature", userhome);
- if ((fp = fopen(bfr, "r")) != NULL) {
- if (mailfp)
- fputs("--", mailfp);
- if (newsfp)
- fputs("-- ", newsfp);
- addbody(fp);
- }
- }
- if (nerrors)
- xxit(1);
-
- if (background) {
- if (fork() > 0)
- exit(0);
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
- #ifdef SIGTSTP
- signal(SIGTSTP, SIG_IGN);
- #endif
- }
- if (mailfp) {
- char **pp;
- char *arg[6];
-
- fclose(mailfp);
- for (pp = addrlist ; pp < addrp ; pp++) {
- arg[0] = MAILER;
- arg[1] = *pp;
- arg[2] = NULL;
- if (runp(arg, mailtemp))
- xerror("Mailer failed");
- }
- }
- if (newsfp) {
- char *arg[6];
- struct stat statb;
-
- fclose(newsfp);
- /* suppress .signature */
- if (userhome == NULL)
- getuser();
- sprintf(signfile, "%s/.signature", userhome);
- if (stat(signfile, &statb) >= 0) {
- chmod(signfile, 0); /* This is sick! */
- signmode = statb.st_mode;
- }
- if (moderator) {
- arg[0] = MAILER;
- arg[1] = moderator;
- arg[2] = NULL;
- if (runp(arg, newstemp))
- xerror("Mail to moderator failed");
- } else {
- arg[0] = XINEWS;
- arg[1] = "-h";
- arg[2] = NULL;
- if (runp(arg, newstemp))
- xerror("inews failed");
- }
- savearticle() ;
- }
- xxit(nerrors? 1 : 0);
- }
-
-
-
- /*
- * Print an error message for an illegal header line.
- */
-
- synerr(fmt, a1, a2, a3, a4)
- char *fmt;
- {
- fprintf(stderr, "postnm: ");
- if (curhdr)
- fprintf(stderr, "line %d: ", curhdr->linno);
- fprintf(stderr, fmt, a1, a2, a3, a4);
- putc('\n', stderr);
- nerrors++;
- }
-
-
- jsynerr(fmt, a1, a2, a3, a4)
- char *fmt;
- {
- synerr(fmt, a1, a2, a3, a4);
- reset();
- }
-
-
-
- xerror(fmt, a1, a2, a3, a4)
- char *fmt;
- {
- fprintf(stderr, "postnm: ");
- fprintf(stderr, fmt, a1, a2, a3, a4);
- putc('\n', stderr);
- xxit(2);
- }
-
-
-
- xxit(status) {
- if (!debug) {
- unlink(newstemp);
- unlink(mailtemp);
- }
- if (signmode) {
- chmod(signfile, signmode);
- }
- exit(status);
- }
-
-
-
- runp(arglist, infile)
- char **arglist;
- char *infile;
- {
- int pid, status, fd;
- extern char *optarg;
- extern int optind;
-
- if (debug) {
- while (*arglist)
- printf("%s ", *arglist++);
- if (infile)
- printf("< %s", infile);
- putchar('\n');
- return 0;
- }
- if (infile && (fd = open(infile, 0)) < 0)
- xerror("Can't open %s", infile);
- if ((pid = fork()) < 0)
- xerror("Can't fork");
- if (pid == 0) {
- if (infile && fd != 0) {
- close(0);
- if (dup(fd) != 0)
- fputs("postnm: dup failed\n", stderr);
- close(fd);
- }
- execv(arglist[0], arglist);
- fprintf(stderr, "Can't exec %s\n", arglist[0]);
- exit(127);
- }
- close(fd);
- while (wait(&status) != pid);
- if (status & 0177) {
- fprintf(stderr, "postnm: %s died with signal %d", arglist[0], status & 0177);
- if (status & 0200)
- fprintf(stderr, " - core dumped");
- putc('\n', stderr);
- } else if (status) {
- fprintf(stderr, "postnm: exit status %d from %s\n", (unsigned) status >> 8, arglist[0]);
- }
- return status;
- }
-
-
-
- /*
- * Save a copy of the article in the users NEWSARCHIVE file.
- * The article is saved only if the user explicitly sets NEWSARCHIVE.
- * Currently, we save USENET articles but not mail, which is
- * rather questionable.
- */
- savearticle() {
- register FILE *in, *out;
- register int c;
- time_t timenow, time();
- char *today, *ctime();
- char *ccname;
- char *getenv();
-
- if ((ccname = getenv("NEWSARCHIVE")) == NULL || ccname[0] == '\0')
- return;
- if ((in = fopen(newstemp, "r")) == NULL) {
- xerror("Can't reopen %s", newstemp);
- }
- if ((out = fopen(ccname, "a")) == NULL) {
- xerror("Can't open %s to save article", ccname);
- }
- timenow = time((time_t *)0);
- today = ctime(&timenow);
- fprintf(out, "From postreply %s", today);
- while ((c=getc(in)) != EOF)
- putc(c, out);
- putc('\n', out);
- fclose(in);
- fclose(out);
- }
- !E!O!F!
-
- cat > postnews/postnm2.c <<\!E!O!F!
- /*
- * Pass one: read in the article.
- *
- * Copyright 1984 by Kenneth Almquist. All rights reserved.
- * Permission is granted for anyone to use and distribute, but not
- * sell, this program provided that this copyright notice is retained.
- */
-
- #include "postnm.h"
-
- /* values of ht_legal */
- #define DITTO 0 /* alias for previous name */
- #define LEGAL 1 /* normal field */
- #define ONCE 2 /* field may only occur once */
- #define ILLEGAL 3 /* user not allowed to specify this field */
-
- struct htype {
- char *ht_name; /* name of header field */
- int ht_legal; /* whether field is legal */
- int ht_type; /* field type number */
- }
- htype[] = {
- "To", LEGAL, HTTO,
- "Cc", LEGAL, HTCC,
- "Bcc", LEGAL, HTBCC,
- "Newsgroups", ONCE, HTNEWSGROUPS,
- "Newsgroup", DITTO, HTNEWSGROUPS,
- "In-Reply-To", ONCE, HTINREPLYTO,
- "References", ONCE, HTREFERENCES,
- "Subject", ONCE, HTSUBJECT,
- "Expires", ONCE, HTEXPIRES,
- "From", ONCE, HTFROM,
- "Reply-To", ONCE, HTREPLYTO,
- "Followup-To", ONCE, HTFOLLOWUPTO,
- "Distribution", ONCE, HTDIST,
- "Dist", DITTO, HTDIST,
- "Keywords", LEGAL, HTKEYWORDS,
- "Control", ONCE, HTCONTROL,
- "Organization", ONCE, HTORGANIZATION,
- "Summary", ONCE, HTSUMMARY,
- "Approved", ONCE, HTAPPROVED,
- "Comments", LEGAL, HTCOMMENTS,
- "Message-Id", ONCE, HTMESSAGEID,
- "Command", ONCE, HTCOMMAND,
- "Article-I.d.", ILLEGAL,HTUNKNOWN,
- "Sender", ILLEGAL,HTUNKNOWN,
- "Resent-Sender", ILLEGAL,HTUNKNOWN,
- "Path", ILLEGAL,HTUNKNOWN,
- "Received", ILLEGAL,HTUNKNOWN,
- NULL, LEGAL, HTUNKNOWN
- };
-
- /*
- * Read in the header.
- */
-
- readheader() {
- setexit();
- while (gethline(infp) != EOF) {
- prochdr(bfr, 0);
- }
- }
-
-
-
- prochdr(val, faked)
- char *val;
- {
- char htname[64];
-
- curhdr = ckmalloc(sizeof *curhdr);
- curhdr->linno = !faked? linno : 0;
- curhdr->text = savestr(val);
- curhdr->fixed = NULL;
- scanp = curhdr->text; /* scan input line */
- if (scnchr(" \t\n:") == 0)
- jsynerr("Illegal header line type");
- if (scanp - curhdr->text > 63)
- jsynerr("Header line type too long");
- getval(curhdr->text, scanp, htname);
- fixcase(htname);
- skipbl();
- if (*scanp++ != ':')
- jsynerr("No colon on header line\nDid you remember to leave a blank line after the article header?");
- skipbl();
- curhdr->body = scanp;
- if (*scanp == '\0')
- curhdr->body--;
-
- gettype(htname, curhdr);
-
- appheader(curhdr, hlast);
- }
-
-
-
- gettype(htname, hp)
- char *htname;
- struct hline *hp;
- {
- register struct htype *htp;
-
- for (htp = htype ; htp->ht_name != NULL && !equal(htp->ht_name, htname) ; htp++);
- if (htp->ht_name == NULL) {
- for (htp = htype ;
- htp->ht_name && (htp->ht_legal == ILLEGAL || !misspells(htp->ht_name, htname)) ;
- htp++);
- if (htp->ht_name != NULL)
- synerr("You misspelled \"%s\"", htp->ht_name);
- }
- while (htp->ht_legal == DITTO)
- htp--;
- hp->type = htp->ht_type;
- if (htp->ht_name == NULL) {
- hp->hdrname = savestr(htname);
- } else {
- hp->hdrname = htp->ht_name;
- if (htp->ht_legal == ILLEGAL)
- jsynerr("You cannot include a \"%s:\" header", htname);
- else if (htp->ht_legal == ONCE && hdrline[hp->type])
- jsynerr("Only one \"%s:\" header line is permitted", htname);
- hdrline[hp->type] = hp;
- }
- }
-
-
- /*
- * Get the correct combination of upper case and lower case in a header
- * line name. The first character and any character immediatly following
- * a minus sign is capitalized. Everything else to lower case.
- */
-
- fixcase(p)
- register char *p;
- {
- int flag = 1;
-
- while (*p) {
- if (*p == '-')
- flag = 1;
- else if (flag) {
- flag = 0;
- if (islower(*p))
- *p = toupper(*p);
- } else {
- if (isupper(*p))
- *p = tolower(*p);
- }
- p++;
- }
- }
-
-
-
- misspells(word, incorrect)
- char *word, *incorrect;
- {
- int i = strlen(word), j = strlen(incorrect);
- register char *p = word, *q = incorrect;
-
- if (j != i && j != i + 1 && j != i - 1)
- return 0;
- while (*p == *q && *p)
- p++, q++;
- if (i > j) {
- if (equal(p + 1, q)) return 1;
- } else if (i < j) {
- if (equal(p, q + 1)) return 1;
- } else {
- if (equal(p + 1, q + 1)) return 1;
- if (p[0] == q[1] && p[1] == q[0] && equal(p + 2, q + 2))
- return 1;
- }
- return 0;
- }
-
-
-
-
- /*
- * Insert a header after the given header, or at the beginning of
- * the list if NULL is given.
- */
-
- appheader(hp, after)
- struct hline *hp, *after;
- {
- struct hline **hpp;
-
- if (after)
- hpp = &after->next;
- else
- hpp = &hfirst;
- hp->next = *hpp;
- *hpp = hp;
- if (hlast == after)
- hlast = hp;
- }
-
-
-
-
- /*
- * Read a header line into bfr, handling continuations.
- */
-
-
- gethline(fp)
- register FILE *fp;
- {
- char *p;
- register char *q;
- int c;
- static int nextlinno = 1;
-
- linno = nextlinno;
- if (feof(fp))
- return EOF;
- p = bfr;
- do {
- if (fgets(p, bfr + LBUFLEN - p, fp) == NULL)
- return EOF;
- if (bfr[0] == '\n')
- return EOF;
- for (q = p ; *q != '\0' && *q != '\n' ; q++) {
- if ((*q < ' ' && *q != '\t') || *q > '~') {
- fprintf(stderr, "postnm: line %d: illegal character (octal %o)\n",
- nextlinno, *(unsigned char *)q);
- nerrors++;
- }
- }
- if (*q == '\0') {
- if (strlen(bfr) != LBUFLEN - 1)
- xerror("line %d: EOF in middle of header line", nextlinno);
- else
- xerror("line %d: Line too long", nextlinno);
- }
- nextlinno++;
- p = q + 1;
- } while (ungetc(c = getc(fp), fp), c == ' ' || c == '\t');
- return 0;
- }
-
-
-
- /*
- * Copy the body of the article to the mail and/or news file. We have to
- * check for:
- * 1) Control characters.
- * 2) Lines consisting of a single '.'
- * 3) Trailing blank lines, which we silently delete.
- * 4) Article which might trigger line eater bug.
- */
-
- addbody(in)
- register FILE *in;
- {
- register int c;
- register FILE *mail = mailfp, *news = newsfp;
- int nlcount = 1; /* force initial blank line */
- int dotflag = 0; /* test for line containing single dot */
- int first = 1; /* avoid line eater */
-
- linno++;
- if (!feof(in))
- while ((c = getc(in)) != EOF) {
- if (c == '\n') {
- if (dotflag)
- xerror("line %d: some versions of mail and news choke on lines consisting of a single dot", linno - nlcount);
- linno++;
- nlcount++;
- } else if (!isprint(c) && !isspace(c) && c != '\b') {
- if (in == infp)
- fprintf(stderr, "line %d: illegal character (octal %o)\n", linno, c);
- else
- fprintf(stderr, "illegal character in signature file (octal %o)\n", c);
- nerrors++;
- } else {
- if (nlcount) {
- if (first) {
- first = 0;
- if ((c == '\t' || c == ' ') && nlcount == 1 && news && in == infp)
- putc('\n', news);
- }
- if (c == '.')
- dotflag++;
- do {
- if (mail)
- putc('\n', mail);
- if (news)
- putc('\n', news);
- } while (--nlcount > 0);
- } else
- dotflag = 0;
- if (mail)
- putc(c, mail);
- if (news)
- putc(c, news);
- }
- }
- if (mail)
- putc('\n', mail);
- if (news)
- putc('\n', news);
- if (mail) {
- fflush(mail);
- if (ferror(mail))
- xerror("write error on temp file");
- }
- if (news) {
- fflush(news);
- if (ferror(news))
- xerror("write error on temp file");
- }
- }
- !E!O!F!
-
- cat > postnews/postnm3.c <<\!E!O!F!
- /*
- * Pass 2: Check header lines for errors.
- *
- * Copyright 1984 by Kenneth Almquist. All rights reserved.
- * Permission is granted for anyone to use and distribute, but not
- * sell, this program provided that this copyright notice is retained.
- */
-
- #include "postnm.h"
-
- char *cmsg[] = { /* list of control messages */
- "cancel",
- "version",
- "ihave",
- "sendme",
-
- "newgroup",
- "rmgroup",
- "sendsys",
- "senduuname",
- "checkgroups",
- "delsub",
- NULL
- };
- #define PRIVCMSG (&cmsg[4]) /* start of priviledged control messages */
-
-
-
- checkheader() {
- char *p, *q;
- struct hline *hp;
-
- curhdr = hdrline[HTSUBJECT];
- if (curhdr == NULL) {
- if (hdrline[HTCONTROL]) {
- sprintf(bfr, "Subject: %s", hdrline[HTCONTROL]->body);
- prochdr(bfr, 1);
- } else {
- fprintf(stderr, "postnm: no subject line\n");
- nerrors++;
- }
- }
- setexit();
- if (hdrline[HTCOMMAND]) {
- hlselect(hdrline[HTCOMMAND]);
- hlzap(HTCOMMAND);
- skipbl();
- p = scanp;
- scnchr(" \t\n");
- q = scanp;
- skipws(" \t\n");
- if (*scanp != '\0')
- cmdjsynerr: jsynerr("Command must be \"reply\", \"followup\", or \"both\"");
- *q = '\0';
- if (equal(p, "reply") || equal(p, "r"))
- hlzap(HTNEWSGROUPS), hlzap(HTDIST);
- else if (equal(p, "followup") || equal(p, "f"))
- hlzap(HTTO);
- else if (!equal(p, "both"))
- goto cmdjsynerr;
- }
-
- for (hp = hfirst ; hp ; hp = hp->next) {
- fixheader(hp);
- }
- if (references && hdrline[HTNEWSGROUPS] && !hdrline[HTREFERENCES]) {
- sprintf(bfr, "References: %s", references);
- prochdr(bfr, 1);
- }
- hlzap(HTBCC);
- cknewsgroups();
- *addrp = NULL;
- }
-
-
-
- /*
- * Process a header line.
- */
-
- fixheader(hp)
- struct hline *hp;
- {
- extern char *begaddr, *endaddr;
- char *p;
- register char **pp;
- time_t tim;
- struct tm *tm;
- static char month[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-
- if (setexit())
- return;
- hlselect(hp);
- switch (hp->type) {
- case HTTO:
- case HTCC:
- case HTBCC:
- for (;;) {
- skipws(" \t\n,");
- if (*scanp == '\0')
- break;
- if (addrp >= &addrlist[MAXADDR])
- jsynerr("too many mail addresses");
- parseaddr();
- *addrp++ = getval(begaddr, endaddr, NULL);
- }
- break;
-
- case HTDIST:
- commalist();
- for (pp = nlist ; *pp ; pp++)
- if (equal(*pp, "net"))
- *pp = "world";
- rmdup(nlist);
- if (nlist[0] == NULL || nlist[1] == NULL && equal(nlist[0], "world"))
- hlzap(HTDIST);
- else
- ckdist();
- for (pp = nlist ; *pp ; pp++)
- if (equal(*pp, "world"))
- *pp = "net";
- goto outlist;
-
- case HTFOLLOWUPTO:
- commalist();
- if (nlist[0] == NULL)
- jsynerr("empty followup-to line");
- rmdup(nlist);
- bcopy((char *)nlist, (char *)follist, sizeof follist);
- goto outlist;
-
- case HTNEWSGROUPS:
- commalist();
- if (nlist[0] == NULL)
- jsynerr("empty newsgroups line");
- rmdup(nlist);
- bcopy((char *)nlist, (char *)nglist, sizeof nglist);
-
- outlist: outp = bfr;
- if (nlist[0]) {
- for (pp = nlist ; *pp ; pp++) {
- if (outp != bfr)
- outstr(",");
- outstr(*pp);
- }
- outstr("\n");
- hp->fixed = savestr(bfr);
- }
- break;
-
- case HTEXPIRES:
- if ((tim = cgtdate(scanp)) == -1L)
- jsynerr("Can't parse date");
- tm = gmtime(&tim);
- sprintf(bfr, "%d %s %d %02d:%02d:%02d GMT\n", tm->tm_mday,
- month[tm->tm_mon], tm->tm_year, tm->tm_hour, tm->tm_min,
- tm->tm_sec);
- hp->fixed = savestr(bfr);
- break;
-
- case HTCONTROL:
- p = scanp;
- scnchr(" \t\n");
- getval(p, scanp, bfr);
- for (pp = cmsg ; *pp && !equal(*pp, bfr) ; pp++);
- if (*pp == NULL)
- jsynerr("Unknown control message \"%s\"", bfr);
- else if (pp >= PRIVCMSG && !isadmin())
- jsynerr("Get your system administrator to send this control message for you.");
- break;
-
- case HTSUBJECT:
- if (*scanp == '\n')
- jsynerr("empty subject line");
- if (prefix(scanp, "cmsg "))
- jsynerr("subjects beginning with cmsg confuse inews");
- if (prefix(scanp, "Re: ") && !hdrline[HTREFERENCES] && !references)
- jsynerr("followup articles must have references lines");
- break;
-
- case HTREFERENCES:
- if (references && !equal(scanp, references)) {
- fprintf(stderr, "postnm: line %d: you changed the references line but I fixed it\n", curhdr->linno);
- curhdr->fixed = references;
- }
- break;
-
- case HTAPPROVED:
- ckapproved();
- break;
-
- case HTORGANIZATION:
- {
- /* Inews ignores organization lines */
- /* I shouldn't have to do this */
- char **pp, **qq;
- extern char **environ;
- sprintf(bfr, "ORGANIZATION=%s", scanp);
- nstrip(bfr);
- envkludge[0] = savestr(bfr);
- qq = envkludge + 1;
- for (pp = environ ; pp < environ + 199 && *pp ; pp++)
- if (!prefix(*pp, "ORGANIZATION="))
- *qq++ = *pp;
- *qq = 0;
- environ = envkludge;
- }
- break;
-
- default:
- break;
- }
- }
-
-
-
- /*
- * Check that newsgroups or distributions are legal.
- */
-
- checklist(file, thing)
- char *file, *thing;
- {
- char fname[FPATHLEN];
- FILE *fp;
- char *left[MAXGRPS + 1], **pp;
-
- sprintf(fname, "%s/%s", LIB, file);
- fp = ckfopen(fname, "r");
- bcopy((char *)nlist, (char *)left, sizeof(left));
- while (fgets(bfr, LBUFLEN, fp) != NULL) {
- scanp = bfr;
- scnchr(" \t");
- *scanp = '\0';
- for (pp = left ; *pp ; pp++) {
- if (equal(*pp, bfr)) {
- do *pp = *(pp + 1);
- while (*pp++);
- break;
- }
- }
- }
- fclose(fp);
- for (pp = left ; *pp ; pp++)
- synerr("illegal %s %s", thing, *pp);
- }
-
-
-
- /*
- * Check distributions for validity. If they aren't in the distributions
- * file, we try the active file.
- */
-
- ckdist() {
- FILE *fp;
- char *p;
- char **pp;
- char *dlist[MAXGRPS + 1];
-
- bcopy((char *)nlist, (char *)dlist, sizeof dlist);
- sprintf(bfr, "%s/distributions", LIB);
- if ((fp = fopen(bfr, "r")) != NULL) {
- while (dlist[0] && fgets(bfr, LBUFLEN, fp)) {
- if (bfr[0] == '\n' || bfr[0] == '#')
- continue;
- if ((p = strpbrk(bfr, " \t\n")) == NULL)
- continue;
- *p = '\0';
- rmlist(bfr, dlist);
- }
- fclose(fp);
- }
- else printf("postnm: warning: no distributions file\n");
- if (dlist[0]) {
- sprintf(bfr, "%s/active", LIB);
- fp = ckfopen(bfr, "r");
- while (dlist[0] && fgets(bfr, LBUFLEN, fp)) {
- if ((p = strpbrk(bfr, " \n")) == NULL)
- continue;
- *p = '\0';
- for (pp = dlist ; *pp ; ) {
- if (ngmatch(bfr, *pp))
- rmlist(*pp, dlist);
- else
- pp++;
- }
- }
- fclose(fp);
- }
-
- prtbad(dlist, "distribution", curhdr);
- }
-
-
-
- /*
- * Check the newsgroups on the Newsgroups: and Followup-To: lines
- * for validity. We do both at once so that we only have to scan
- * the active file once.
- */
-
- cknewsgroups() {
- FILE *actfp;
- char *p;
- int didng = 0;
- char **pp;
-
- if (nglist[0] == NULL && follist[0] == NULL)
- return;
- bcopy((char *)nglist, (char *)nlist, sizeof nlist);
- sprintf(bfr, "%s/active", LIB);
- actfp = ckfopen(bfr, "r");
- while ((nlist[0] || follist[0]) && fgets(bfr, LBUFLEN, actfp)) {
- if ((p = index(bfr, ' ')) == NULL && (p = index(bfr, '\n')) == NULL)
- continue;
- *p = '\0';
- if (rmlist(bfr, nlist) >= 0)
- didng = 1;
- rmlist(bfr, follist);
- }
- fclose(actfp);
-
- /* Not all newsgroups on followup need be legal */
- if (nlist[0] && (!hdrline[HTREFERENCES] || !didng))
- prtbad(nlist, "newsgroup", hdrline[HTNEWSGROUPS]);
- else {
- /* check for moderated groups */
- for (pp = nglist ; *pp ; pp++) {
- if (hdrline[HTAPPROVED] == NULL && ngmatch(*pp, MODGROUPS)) {
- getmod(*pp);
- break;
- }
- }
- }
- prtbad(follist, "newsgroup", hdrline[HTFOLLOWUPTO]);
- }
-
-
- prtbad(pp, what, hl)
- char **pp;
- char *what;
- struct hline *hl;
- {
- hlselect(hl);
- while (*pp)
- synerr("Bad %s %s", what, *pp++);
- }
-
-
-
- /*
- * Remove an entry from an array of character strings.
- */
-
- rmlist(entry, list)
- char *entry, **list;
- {
- register char **pp;
- register char **qq;
- int retval;
-
- qq = list;
- retval = -1;
- for (pp = list ; *pp ; pp++) {
- if (!equal(*pp, entry))
- *qq++ = *pp;
- else
- retval = 0; /* removed one */
- }
- *qq = NULL;
- return retval;
- }
-
-
-
- /*
- * Check "Approved:" line. Currently, we require an address which must
- * include an at sign and which cannot be enclosed in angle brackets.
- * An optional real name in parenthesis is allowed, but not other comments.
- */
-
- ckapproved() {
- char *start = scanp;
- extern char *beglocal, *endlocal, *begdomain;
-
- if (*scanp == '(' || *scanp == ',' || *scanp == '\n')
- bad: jsynerr("Illegal address");
- parseaddr();
- if (beglocal != start || *endlocal != '@' || begdomain != endlocal + 1)
- goto bad;
- skipbl();
- if (*scanp)
- goto bad;
- }
-
-
-
- /*
- * Parse a comma separated list into its components.
- */
-
- commalist() {
- char **pp;
- char *p;
-
- pp = nlist;
- for (;;) {
- skipws(" \t\n,");
- if (*scanp == '\0')
- break;
- p = scanp;
- scnchr(" \t\n,(");
- if (pp >= nlist + MAXGRPS)
- jsynerr("list too long");
- *pp++ = getval(p, scanp, NULL);
- }
- *pp = NULL;
- }
-
-
-
- outstr(str)
- char *str;
- {
- strcpy(outp, str);
- outp += strlen(str);
- }
-
-
-
- rmdup(list)
- char **list;
- {
- register char **pp, **qq;
-
- while (*list) {
- for (pp = qq = list + 1 ; *pp ; pp++)
- if (!equal(*pp, *list))
- *qq++ = *pp;
- *qq = NULL;
- list++;
- }
- }
-
-
-
- /*
- * Set up a given header for parsing.
- */
-
- hlselect(hp)
- struct hline *hp;
- {
- curhdr = hp;
- scanp = hp->body;
- }
-
-
- hlzap(type)
- int type;
- {
- register struct hline *hp, **prev;
-
- prev = &hfirst;
- while ((hp = *prev) != NULL) {
- if (hp->type == type)
- *prev = hp->next; /* delete line */
- else
- prev = &hp->next;
- }
- hdrline[type] = NULL;
- hlast = NULL;
- for (hp = hfirst ; hp ; hp = hp->next)
- hlast = hp;
- }
-
-
-
- /*
- * Figure out the moderator of a group.
- */
-
- getmod(newsgroup)
- char *newsgroup;
- {
- FILE *fp;
- char *p;
- char *q;
- char s[BUFLEN];
- FILE *popen();
-
- sprintf(bfr, "%s/moderators", LIB);
- fp = ckfopen(bfr, "r");
- for (;;) {
- if (fgets(bfr, LBUFLEN, fp) == NULL)
- goto notfound;
- if ((p = strpbrk(bfr, " \t")) == NULL)
- continue; /* "Can't happen" */
- *p++ = '\0';
- if (equal(bfr, newsgroup))
- break;
- }
- fclose(fp);
- while (*p == ' ' || *p == '\t')
- p++;
- nstrip(p);
- moderator = savestr(p);
- return;
-
- notfound:
- fclose(fp);
-
- /* try to use return path from old article */
- sprintf(bfr, "%s/active", LIB);
- fp = ckfopen(bfr, "r");
- while (fgets(bfr, LBUFLEN, fp) != NULL) {
- p = index(bfr, ' ');
- *p++ = '\0';
- if (equal(bfr, newsgroup))
- break;
- }
- fclose(fp);
- if ((q = strpbrk(p, " \t\n")) != NULL)
- *q = '\0';
- scopyn(p, s, 32);
- dirname(newsgroup, bfr);
- sprintf(bfr + strlen(bfr), "/%ld", atol(s));
- printf("postnm: trying to find moderator for %s from %s\n", newsgroup, bfr);
- if ((fp = fopen(bfr, "r")) != NULL) {
- while (fgets(bfr, LBUFLEN, fp) != NULL && bfr[0] != '\n') {
- #ifdef notdef /* "From:" line has same info */
- if (prefix(bfr, "Path:")) {
- scanp = bfr + 5;
- s[0] = '\0';
- for (;;) {
- scchr("!:@^% \t\n");
- p = scanp;
- scnchr("!:@^% \t\n");
- q = scanp;
- scchr("!:@^% \t\n");
- if (*scanp)
- getval(p, q, s);
- else
- break;
- }
- if (s[0] == '\0')
- continue;
- if (index(s, '.') == NULL)
- strcat(s, ".UUCP");
- *q = '\0';
- sprintf(bfr, "%s@%s", p, s);
- moderator = savestr(bfr);
- printf("postnm: assuming moderator for %s is %s\n", newsgroup, bfr);
- }
- #endif
- if (prefix(bfr, "From:")) {
- getaddr(bfr + 5, s);
- moderator = savestr(s);
- }
- else if (prefix(bfr, "Approved:")) {
- getaddr(bfr + 9, s);
- moderator = savestr(s);
- }
- }
- }
-
- if (fp != NULL)
- fclose(fp);
- if (! moderator)
- synerr("Can\'t find moderator for newsgroup %s", newsgroup);
- #ifdef NOTIFY
- sprintf(bfr, "mail \'%s\'", NOTIFY);
- #else
- sprintf(bfr, "mail \'%s\'", ADMIN);
- #endif
- if ((fp = popen(bfr, "w")) == NULL)
- fprintf(stderr, "postnm: can\'t send mail to administrator\n");
- else {
- fprintf(fp, "Subject: missing moderator entry for %s\n\n", newsgroup);
- fprintf(fp, "From: The postnm program.\n");
- fprintf(fp, "\nThere is no entry for %s in %s/moderators\n",
- newsgroup, LIB);
- if (moderator)
- fprintf(fp, "The moderator is probably %s\n", moderator);
- pclose(fp);
- }
- }
- !E!O!F!
-
- cat > postnews/postnm4.c <<\!E!O!F!
- /*
- * Pass 3: generate the news and mail headers.
- *
- * Copyright 1984 by Kenneth Almquist. All rights reserved.
- * Permission is granted for anyone to use and distribute, but not
- * sell, this program provided that this copyright notice is retained.
- */
-
- #include "postnm.h"
-
-
- /*
- * Write out a header.
- */
- gennewshdr(fp)
- FILE *fp;
- {
- int didmod = 0;
-
- for (curhdr = hfirst ; curhdr ; curhdr = curhdr->next) {
- if (setexit()) continue;
- switch (curhdr->type) {
- case HTFROM:
- case HTREPLYTO:
- newsaddr(curhdr);
- break;
-
- case HTTO:
- fputs("To: ", fp);
- if (moderator && ! didmod)
- fprintf(fp, "%s (The Moderator), ", moderator);
- fputs(curhdr->body, fp);
- didmod = 1;
- break;
-
- default:
- if (curhdr->fixed)
- fprintf(fp, "%s: %s", curhdr->hdrname, curhdr->fixed);
- else
- fprintf(fp, "%s: %s", curhdr->hdrname, curhdr->body);
- break;
- }
- }
- if (moderator && !didmod)
- fprintf(fp, "To: %s (The Moderator)\n", moderator);
- }
-
-
- genmailhdr(fp)
- FILE *fp;
- {
- for (curhdr = hfirst ; curhdr ; curhdr = curhdr->next) {
- if (setexit()) continue;
- switch (curhdr->type) {
- case HTREFERENCES:
- if (hdrline[HTINREPLYTO] == NULL) {
- register char *p, *q;
- p = curhdr->fixed? curhdr->fixed : curhdr->body;
- if ((p = rindex(p, '<')) != NULL
- && (q = index(p, '>')) != NULL) {
- fprintf(fp, "In-reply-to: USENET article %s\n",
- getval(p, q + 1, bfr));
- }
- }
- break;
-
- case HTEXPIRES:
- fputs(curhdr->text, fp);
- break;
-
- default:
- if (curhdr->fixed)
- fprintf(fp, "%s: %s", curhdr->hdrname, curhdr->fixed);
- else
- fputs(curhdr->text, fp);
- break;
- }
- }
- }
-
-
-
- newsaddr(hp)
- struct hline *hp;
- {
- char domain[NAMELEN], local[NAMELEN];
- extern char *begreal, *endreal; /* real name */
- extern char *beglocal, *endlocal; /* local part */
- extern char *begdomain, *enddomain; /* domain part */
-
- hlselect(hp);
- skipws(" \t\n,");
- parseaddr();
- skipws(" \t\n,");
- if (*scanp != '\0') {
- synerr("only one address permitted on \"%s:\" line", hp->hdrname);
- return;
- }
- if (begdomain)
- getval(begdomain, enddomain, domain);
- else
- sprintf(domain, "%s%s", FULLSYSNAME, MYDOMAIN);
- getval(beglocal, endlocal, local);
- fprintf(newsfp, "%s: %s@%s", hp->hdrname, local, domain);
- if (begreal) {
- getval(begreal, endreal, bfr);
- fprintf(newsfp, " (%s)", bfr);
- }
- putc('\n', newsfp);
- if (equal(hp->hdrname, "From")
- && (index(local, '!') || index(domain, '!') || index(bfr, '!')))
- synerr("Exclamation points on From: line break inews");
- }
- !E!O!F!
-
- echo Part 5 of 7 extracted.
-
-
-